/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://dylab.googlecode.com

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

#ifndef __dylab_BitFlags_h__
#define __dylab_BitFlags_h__

//===========================================================================================
#include <dylab/utils/types/TypeTraits.h>

//===========================================================================================
namespace dylab {

    /** 
     */    
    template < 
        typename _DataT
    >
    class BitFlags
    {
    public:        
        typedef typename _DataT data_t;

    public:
        template <class _BitFlagsT>
        static _BitFlagsT parse(const String & _string, uint32_t _flagsCount, const String & _separators = " ,")
                {
                    // tokenize the string
                    TokenParser tokens(_string, _separators);

                    // check the number of tokens - it has to match the _flagsCount
                    if (tokens.getTokens().getCount() != _flagsCount)
                        throw EInvalidFormat(
							String::fmt("Number of tokens in string '%1%' does not match the number of flags (%2%)", 
								_string, _flagsCount));

                    // the tokens corresponds to the vector components
                    _BitFlagsT bitFlags;
                    for (uint32_t i = 0; i < _flagsCount; i++)
                        bitFlags.change(i, tokens.getTokens()[i].parse<bool>());

                    // return the parsed bitFlags
                    return bitFlags;
                }

    private:
        _DataT mFlags;

    public:

        /**
        */
        BitFlags()
                { }

        /**
        */
        BitFlags(_DataT _flags)
            : mFlags(_flags)
                { }

        /**
        */
        virtual ~BitFlags()
                { }

        /**
        */
        void setFlags(_DataT _flags)
                { mFlags |= _flags; }

        /**
        */
        _DataT getFlags() const
                { return mFlags; }

        /**
        */
        void clearFlags(_DataT _flags)
                { mFlags &= ~_flags; }

        /**
        */
        void clearAllFlags()
                { mFlags = 0; }

        /**
        */
        bool testFlags(_DataT _flags) const
                { return (mFlags & _flags) != 0; }

        /**
        */
        void flipFlags(_DataT _flags)
                { mFlags ^= _flags; }

        /**
        */
        bool test(uint32_t _flagIndex) const
                { return testFlags(_flagIndexToNum(_flagIndex)); }

        /**
        */
        void set(uint32_t _flagIndex)
                { setFlags(_flagIndexToNum(_flagIndex)); }
        /**
        */
        void clear(uint32_t _flagIndex)
                { clearFlags(_flagIndexToNum(_flagIndex)); }
        /**
        */
        void flip(uint32_t _flagIndex)
                { flipFlags(_flagIndexToNum(_flagIndex)); }

        /**
        */
        void change(uint32_t _flagIndex, bool _flagValue)
                { 
                    if (_flagValue) 
                        set(_flagIndex); 
                    else
                        clear(_flagIndex);
                }

    private:
        _DataT _flagIndexToNum(uint32_t _flagIndex) const
                {
                    DYLAB_ASSERT(_flagIndex < TypeTraits<_DataT>::numberOfBits());
                    return 1 << _flagIndex;
                }
    };

    //===========================================================================================
    // 8-bit flags
    class DYLAB_EXPORT BitFlags8 
        : public BitFlags<uint8_t>
    {
    public:
        static BitFlags8 parse(const String & _string, uint32_t _flagsCount, const String & _separators = " ,")
                { return BitFlags<uint8_t>::parse<BitFlags8>(_string, _flagsCount, _separators); }
    public:
        BitFlags8()
                { }
        BitFlags8(uint8_t _flags)
            : BitFlags<uint8_t>(_flags)
                { }
    };

    //===========================================================================================
    // 16-bit flags
    class DYLAB_EXPORT BitFlags16 
        : public BitFlags<uint16_t>
    {
    public:
        static BitFlags16 parse(const String & _string, uint32_t _flagsCount, const String & _separators = " ,")
                { return BitFlags<uint16_t>::parse<BitFlags16>(_string, _flagsCount, _separators); }
    public:
        BitFlags16()
                { }
        BitFlags16(uint16_t _flags)
            : BitFlags<uint16_t>(_flags)
                { }
    };

    //===========================================================================================
    // 32-bit flags
    class DYLAB_EXPORT BitFlags32 
        : public BitFlags<uint32_t>
    {
    public:
        static BitFlags32 parse(const String & _string, uint32_t _flagsCount, const String & _separators = " ,")
                { return BitFlags<uint32_t>::parse<BitFlags32>(_string, _flagsCount, _separators); }
    public:
        BitFlags32()
                { }
        BitFlags32(uint32_t _flags)
            : BitFlags<uint32_t>(_flags)
                { }
    };
}
//===========================================================================================
#endif // __dylab_BitFlags_h__
